﻿using System;
using System.Collections.Generic;

namespace SportManager
{
    /// <summary>
    /// Training type
    /// </summary>
    public enum TrainingType
    {
        Common = 0,
        Strength,
        Endurance,
        Hypertrophy,
        Fatloss,
        Athletic
    }

    [Serializable]
    public class Training : DataHolder
    {
        private static readonly DateTime m_StartOfTraining = new DateTime(1, 1, 1, 21, 00, 0);
        private static readonly DateTime m_EndOfTraining   = new DateTime(1, 1, 1, 22, 30, 0);
        
        public Training(int year, int month, int day, Guid guid)
        {
            StartDate = new DateTime(year, month, day, m_StartOfTraining.Hour
                , m_StartOfTraining.Minute, m_StartOfTraining.Second
            );

            FinishDate = new DateTime(year, month, day, m_EndOfTraining.Hour
                , m_EndOfTraining.Minute, m_EndOfTraining.Second
            );

            Id = guid;
            Exercises = new List<Exercise>();
            Type = TrainingType.Common;
            IsReadOnly = false;
            Update();
        }
        /// <summary>
        /// Function for Training comparison by Date
        /// </summary>
        public static int CompareByDate(Training x, Training y)
        {
            return x.StartDate.CompareTo(y.StartDate);
        }

        #region Training fields
        private TrainingType m_type;
        private List<Exercise> m_exercises;
        private DateTime m_startDate;
        private DateTime m_finishDate;
        private bool m_isReadOnly;
        #endregion

        #region Training Properties
        /// <summary>
        /// Training type
        /// </summary>
        public TrainingType Type
        {
            get
            {
                return m_type;
            }
            set
            {
                m_type = value;
                Update();
            }
        }
        /// <summary>
        /// List of exercises in the training
        /// </summary>
        public List<Exercise> Exercises
        {
            get
            {
                return m_exercises;
            }
            set
            {
                m_exercises = value;
                Update();
            }
        }
        /// <summary>
        /// Start date and time of the training
        /// </summary>
        public DateTime StartDate
        {
            get
            {
                return m_startDate;
            }
            set
            {
                m_startDate = value;
                Update();
            }
        }
        /// <summary>
        /// Finish date and time of the training
        /// </summary>
        public DateTime FinishDate
        {
            get
            {
                return m_finishDate;
            }
            set
            {
                m_finishDate = value;
                Update();
            }
        }
        /// <summary>
        /// Is read-only training
        /// </summary>
        public bool IsReadOnly
        {
            get
            {
                return m_isReadOnly;
            }
            set
            {
                m_isReadOnly = value;
                Update();
            }
        }
        #endregion
    }

    [Serializable]
    public class Approach
    {
        public Approach(int repeats, double weight, int time)
        {
            Weight = weight;
            Repeats = repeats;
            Time = time;
        }

        public Approach()
            : this(0, 0, 0)
        {
        }

        /// <summary>
        /// Weight for approach, kg
        /// </summary>
        public double Weight { get; set; }
        /// <summary>
        /// Count of repeats for approach
        /// </summary>
        public int Repeats { get; set; }
        /// <summary>
        /// Time for approach
        /// </summary>
        public int Time { get; set; }
    }

    [Serializable]
    public class Exercise
    {
        public Exercise(Guid exerciseId, List<Approach> approachs, List<Approach> planningApproachs)
        {
            Id = exerciseId;
            Approachs = approachs;
            PlanningApproachs = planningApproachs;
        }

        /// <summary>
        /// Exercise identifer
        /// </summary>
        public Guid Id { get; set; }
        /// <summary>
        /// List of Approachs for this exercise
        /// </summary>
        public List<Approach> Approachs { get; set; }
        /// <summary>
        /// List of planning Approachs for this exercise
        /// </summary>
        public List<Approach> PlanningApproachs { get; set; }
    }

    /// <summary>
    /// Struct for antropometrical description of human
    /// </summary>
    [Serializable]
    public class AntropometricalData : DataHolder
    {
        [Serializable]
        public class DataItem
        {
            public delegate void UpdateFunction();

            public DataItem(string name, UpdateFunction updater)
            {
                Name = name;
                m_propertyValue = null;
                m_updater = updater;
            }

            public override string ToString()
            {
                return Name;
            }

            /// <summary>
            /// Value of property
            /// </summary>
            public double? Value
            {
                get
                {
                    return m_propertyValue;
                }
                set
                {
                    m_propertyValue = value;
                    m_updater();
                }
            }
            /// <summary>
            /// Name of propoerty
            /// </summary>
            public string Name { get; set; }

            private UpdateFunction m_updater;
            private double? m_propertyValue;
        }

        public AntropometricalData()
        {
            Items = new Dictionary<string, DataItem>();
            DataItem.UpdateFunction function = new DataItem.UpdateFunction(Update);

            Items["Weight"]            = new DataItem("Вес", function);
            Items["Height"]            = new DataItem("Рост", function);
            Items["PercentOfFat"]      = new DataItem("Процент жира", function);
            Items["PercentOfMuscules"] = new DataItem("Процент мускулов", function);
            Items["ChestSize"]         = new DataItem("Объем груди", function);
            Items["BicepsSize"]        = new DataItem("Объем бицепса", function);
            Items["ForearmSize"]       = new DataItem("Объем предплечья", function);
            Items["WristSize"]         = new DataItem("Объем запястья", function);
            Items["NeckSize"]          = new DataItem("Объем шеи", function);
            Items["WaistSize"]         = new DataItem("Объем талии", function);
            Items["PelvisSize"]        = new DataItem("Объем таза", function);
            Items["ThightSize"]        = new DataItem("Объем бедра", function);
            Items["ShinSize"]          = new DataItem("Объем голени", function);
            Items["AnkleSize"]         = new DataItem("Объем лодыжки", function);
        }

        /// <summary>
        /// Function for Antropometric comparison by Date
        /// </summary>
        public static int CompareByDate(AntropometricalData x, AntropometricalData y)
        {
            return x.Date.CompareTo(y.Date);
        }

        #region Antropometrical data properties
        /// <summary>
        /// Measurement date
        /// </summary>
        public DateTime Date 
        {
            get
            {
                return m_date;
            }
            set
            {
                m_date = value;
            }
        }
        /// <summary>
        /// Dictionary of items
        /// </summary>
        public Dictionary<string, DataItem> Items;
        #endregion

        private DateTime m_date;
    }
}